<template>
    <div class="qt-context-menu" :style="contextMenuStyle" v-clickoutside="hide" ref="contextMenu">
        <template v-for="(button, index) in fixedButtons">
            <div v-if="button.type ==='hr'" class="context-menu-separator" :key="index"></div>
            <div v-else-if="button.type ==='more'" :key="index" class="context-menu-item">
                <i :class="button.icon">&nbsp;</i>
                {{button.name}}
                <i class="icon-more el-icon-caret-right"></i>
                <div
                    ref="subContextMenu"
                    class="qt-sub-context-menu"
                    :class="{
                        'qt-sub-context-menu--left': isSubMenuLeft,
                        'qt-sub-context-menu--top': isSubMenuTop,
                        'is-visible': visible
                    }"
                >
                    <template v-for="(childButton, childIndex) in button.children">
                        <div
                            v-if="childButton.type ==='hr'"
                            :key="childIndex"
                            class="context-menu-separator"
                        ></div>
                        <div
                            v-else
                            :key="childButton.name"
                            class="context-menu-item"
                            :class="{'is-disabled': childButton.isDisabled}"
                            @click="handleClick(childButton)"
                        >
                            <i :class="childButton.icon">&nbsp;</i>
                            {{childButton.name}}
                        </div>
                    </template>
                </div>
            </div>
            <div
                v-else
                class="context-menu-item"
                :class="{'is-disabled': button.isDisabled}"
                :key="index"
                @click="handleClick(button)"
            >
                <i :class="button.icon">&nbsp;</i>
                {{button.name}}
            </div>
        </template>
    </div>
</template>

<script>
import lodash from 'lodash';

export default {
    name: 'contextMenu',

    props: {
        buttons: {
            type: Array,
            default() {
                return [];
            }
        },
        selections: {
            type: Array,
            default() {
                return [];
            }
        }
    },

    data() {
        return {
            visible: false,
            x: 0,
            y: 0,
            isPositionFixed: false,
            // 二次菜单显示在左侧，默认显示在右侧
            isSubMenuLeft: false,
            // 二次菜单显示在上面，默认显示在下面
            isSubMenuTop: false
        };
    },

    computed: {
        fixedButtons() {
            let length = this.selections.length;
            return lodash
                .cloneDeep(this.buttons)
                .filter(btn => !btn.isHidden)
                .map(btn => {
                    if (!btn.isDisabled) {
                        if (btn.type === 'single') {
                            btn.isDisabled = length !== 1;
                        } else if (btn.type === 'mutiple') {
                            btn.isDisabled = length <= 0;
                        }
                    }
                    if (btn.children) {
                        btn.children = btn.children
                            .filter(subBtn => !subBtn.isHidden)
                            .map(subBtn => {
                                if (subBtn.type === 'single') {
                                    subBtn.isDisabled = length !== 1;
                                } else if (subBtn.type === 'mutiple') {
                                    subBtn.isDisabled = length <= 0;
                                }
                                return subBtn;
                            });
                    }
                    return btn;
                });
        },
        contextMenuStyle() {
            return {
                left: this.x + 'px',
                top: this.y + 'px',
                visibility: this.visible ? 'visible' : 'hidden',
                position: this.isPositionFixed ? 'fixed' : 'absolute'
            };
        }
    },

    methods: {
        handleClick(btn) {
            if (btn.isDisabled) {
                return;
            }
            this.hide();
            let param = this.selections;
            if (btn.type === 'single') {
                param = this.selections[0];
            }
            if (btn.callback) {
                btn.callback(param);
            }
        },
        // 显示右键菜单
        show({ x, y }, parentEle, flag) {
            let eleRect = this.$refs.contextMenu.getBoundingClientRect();
            let width = eleRect.width;
            let height = eleRect.height;
            let viewportWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
            let viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
            let parentEleRect = parentEle.getBoundingClientRect();
            let parentEleTop = parentEleRect.top;
            let parentEleLeft = parentEleRect.left;
            let parentEleRight = parentEleRect.right;
            let parentEleBottom = parentEleRect.bottom;
            let parentEleHeight = parentEleRect.height;
            let subContextMenuHeights =
                (this.$refs.subContextMenu && this.$refs.subContextMenu.map(el => el.getBoundingClientRect().height)) || [];
            // 二级菜单最大的高度
            let subContextMenuheightMax = Math.max(...subContextMenuHeights);
            if (flag) {
                // 如果是直接挂靠在菜单按钮下面
                this.isPositionFixed = true;
                this.x = parentEleRight - width;
                this.y = parentEleBottom + height > viewportHeight ? parentEleBottom - height - parentEleHeight - 2 : parentEleBottom + 2;
            } else {
                // 右键菜单
                this.isPositionFixed = false;
                this.x = width + x > viewportWidth ? x - width : x;
                this.y = height + y > viewportHeight ? y - height : y;
                // 如果菜单右侧距离右侧距离大于 117 （子菜单宽度 + 滚动条），则显示在右侧
                if (viewportWidth - this.x - width > 217) {
                    this.isSubMenuLeft = false;
                } else {
                    this.isSubMenuLeft = true;
                }
                if (viewportHeight - this.y - height > subContextMenuheightMax) {
                    this.isSubMenuTop = false;
                } else {
                    this.isSubMenuTop = true;
                }
                this.x = this.x - parentEleLeft;
                this.y = this.y - parentEleTop;
                // 防止被遮挡
                if (this.y < 0) {
                    this.y = 0;
                }
            }
            this.visible = true;
        },
        hide() {
            this.visible = false;
        }
    }
};
</script>

<style lang="scss" scoped>
.qt-context-menu {
    border: 1px solid #ddd;
    padding: 2px 0;
    z-index: 100;
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.95);
    box-shadow: 3px 2px 3px 0 rgba(0, 0, 0, 0.44);
}
.context-menu-item {
    position: relative;
    line-height: 30px;
    width: 200px;
    font-size: 12px;
    color: #000;
    cursor: default;
    user-select: none;
    &:hover {
        background: rgba(76, 148, 243, 0.1);
        .qt-sub-context-menu {
            &.is-visible {
                visibility: visible;
            }
        }
    }
    & > i {
        display: inline-block;
        width: 30px;
        line-height: 30px;
        text-align: center;
        color: #419eff;
    }
    &.is-disabled {
        color: #777;
        & > i {
            color: #777;
        }
        &:hover {
            background: rgba(255, 255, 255, 0.95);
        }
    }
    .icon-more {
        border: none;
        float: right;
    }
}
/* 禁用状态 */
.context-menu-separator {
    height: 1px;
    background: #eee;
    border: none;
    margin: 2px 0;
    & + .context-menu-separator {
        display: none;
    }
}
/* 子菜单 */
.qt-sub-context-menu {
    visibility: hidden;
    position: absolute;
    padding: 2px 0;
    left: 100%;
    top: 0;
    border: 1px solid #ddd;
    background: rgba(255, 255, 255, 0.95);
    z-index: 100;
    border-radius: 4px;
    box-shadow: 3px 2px 3px 0 rgba(0, 0, 0, 0.44);
}
.qt-sub-context-menu--left {
    right: 100%;
    left: auto;
}
.qt-sub-context-menu--top {
    top: auto;
    bottom: 0;
}
</style>
